Remove host function definition region dependency #389
Remove host function definition region dependency #389jsturtevant wants to merge 2 commits intohyperlight-dev:mainfrom
Conversation
Instead of using a shared memory region or a host function callback to provide host function definitions to the guest, the host now pushes the serialized definitions directly as a parameter to InitWasmRuntime. Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
rust_wasm_samples, hyperlight_wasm_macro, and component_sample were missing empty [workspace] tables in their Cargo.toml files. Without this, Cargo resolves to the main checkout's workspace root when run from a git worktree, causing 'believes it's in a workspace' errors. wasm_runtime already had this marker. Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
| register_function(GuestFunctionDefinition::new( | ||
| "InitWasmRuntime".to_string(), | ||
| vec![], | ||
| vec![ParameterType::VecBytes], |
There was a problem hiding this comment.
Not strictly related to your PR, but can we use the #[guest_func] macro on init_wasm_runtime instead of manually calling register_function?
There was a problem hiding this comment.
maybe teh same applies to all usages of register_function
There was a problem hiding this comment.
Pull request overview
This PR removes the guest’s dependency on a dedicated “host function definition region” by having the host serialize host function definitions and pass them directly into the guest’s InitWasmRuntime call, aligning with upstream HL-core changes (issue #388).
Changes:
- Update the guest wasm runtime to parse
HostFunctionDetailsfromInitWasmRuntimeparameters (VecBytes) instead of reading from a shared region / callback. - Update the host sandbox initialization to track + serialize registered host function definitions and pass them into
InitWasmRuntime. - Remove
SandboxBuilder::with_function_definition_sizeand document the breaking change; add[workspace]stanzas to excluded crates to avoid workspace resolution issues.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/wasm_runtime/src/module.rs | InitWasmRuntime now expects a VecBytes parameter containing serialized host function details and registers host funcs from it. |
| src/wasm_runtime/src/hostfuncs.rs | Removes the old get_host_function_details() path. |
| src/wasm_runtime/src/component.rs | Updates InitWasmRuntime signature in the component runtime interface (now takes VecBytes). |
| src/hyperlight_wasm/src/sandbox/proto_wasm_sandbox.rs | Tracks host function definitions as they’re registered; serializes and passes them to InitWasmRuntime. |
| src/hyperlight_wasm/src/sandbox/sandbox_builder.rs | Removes the builder API for host function definition region sizing. |
| src/hyperlight_wasm/src/sandbox/loaded_wasm_sandbox.rs | Adds a regression test ensuring missing host functions fail module load. |
| src/hyperlight_wasm/Cargo.toml | Adds hyperlight-common dependency used for flatbuffer wrapper types. |
| Cargo.toml | Adds hyperlight-common to workspace dependencies. |
| Cargo.lock | Locks hyperlight-common dependency. |
| src/rust_wasm_samples/Cargo.toml | Adds [workspace] to make the crate a standalone workspace root when built directly. |
| src/hyperlight_wasm_macro/Cargo.toml | Adds [workspace] to make the crate a standalone workspace root when built directly. |
| src/component_sample/Cargo.toml | Adds [workspace] to make the crate a standalone workspace root when built directly. |
| CHANGELOG.md | Documents the breaking removal of SandboxBuilder::with_function_definition_size. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Track the host function definition for pushing to guest at load time | ||
| self.host_function_definitions.push(HostFunctionDefinition { | ||
| function_name: name.to_string(), | ||
| parameter_types: Some(Args::TYPE.to_vec()), | ||
| return_type: Output::TYPE, | ||
| }); |
There was a problem hiding this comment.
host_function_definitions is built by blindly pushing entries, but you also pre-seed it with a HostPrint definition in new(). If a caller later registers a host function named HostPrint via register(...)/register_host_function(...), the list will contain duplicates and the guest init_wasm_runtime will attempt to linker.func_new the same name twice, which should error and prevent the runtime from loading. Consider enforcing uniqueness by name (e.g., replace existing definition instead of pushing, or special-case HostPrint).
| // Track the host function definition for pushing to guest at load time | |
| self.host_function_definitions.push(HostFunctionDefinition { | |
| function_name: name.to_string(), | |
| parameter_types: Some(Args::TYPE.to_vec()), | |
| return_type: Output::TYPE, | |
| }); | |
| // Track the host function definition for pushing to guest at load time, | |
| // ensuring uniqueness by function name. | |
| if let Some(existing) = self | |
| .host_function_definitions | |
| .iter_mut() | |
| .find(|def| def.function_name == name) | |
| { | |
| existing.parameter_types = Some(Args::TYPE.to_vec()); | |
| existing.return_type = Output::TYPE; | |
| } else { | |
| self.host_function_definitions | |
| .push(HostFunctionDefinition { | |
| function_name: name.to_string(), | |
| parameter_types: Some(Args::TYPE.to_vec()), | |
| return_type: Output::TYPE, | |
| }); | |
| } |
There was a problem hiding this comment.
I did think about this, but wasn't sure what the best thing to do was. Anyone have any thoughts? This feels like it could lead to some strange bugs as well
| // Track the host function definition for pushing to guest at load time | ||
| self.host_function_definitions.push(HostFunctionDefinition { | ||
| function_name: name.as_ref().to_string(), | ||
| parameter_types: Some(Args::TYPE.to_vec()), | ||
| return_type: Output::TYPE, | ||
| }); |
There was a problem hiding this comment.
The logic to append a HostFunctionDefinition is duplicated in both Registerable::register_host_function and the inherent ProtoWasmSandbox::register method. This duplication makes it easy for the two paths to drift (e.g., one adds de-dup or normalization and the other doesn’t). Consider extracting a small helper (or having one method delegate to the other) so the tracking behavior stays consistent.
| _ => { | ||
| return Err(HyperlightGuestError::new( | ||
| ErrorCode::GuestFunctionParameterTypeMismatch, | ||
| "InitWasmRuntime: first parameter must be VecBytes".to_string(), | ||
| )) | ||
| } |
There was a problem hiding this comment.
When parameters is present but empty, this returns "InitWasmRuntime: first parameter must be VecBytes", which is a bit misleading (the real issue is that no parameters were provided). Consider explicitly handling the empty-vec case and returning a clearer error (e.g., "expected 1 parameter") to make debugging host/guest ABI mismatches easier.
| _ => { | |
| return Err(HyperlightGuestError::new( | |
| ErrorCode::GuestFunctionParameterTypeMismatch, | |
| "InitWasmRuntime: first parameter must be VecBytes".to_string(), | |
| )) | |
| } | |
| Some(_) => { | |
| return Err(HyperlightGuestError::new( | |
| ErrorCode::GuestFunctionParameterTypeMismatch, | |
| "InitWasmRuntime: first parameter must be VecBytes".to_string(), | |
| )) | |
| } | |
| None => { | |
| return Err(HyperlightGuestError::new( | |
| ErrorCode::GuestFunctionParameterTypeMismatch, | |
| "InitWasmRuntime: expected 1 parameter".to_string(), | |
| )) | |
| } |
Instead of using a shared memory region or a host function callback
to provide host function definitions to the guest, the host now pushes
the serialized definitions directly as a parameter to InitWasmRuntime.
fixes #388